package com.cscec81.passport.base.oauth2.server.authorization.token;

import org.springframework.lang.Nullable;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
import org.springframework.util.Assert;

import java.util.*;

public class IamAuthenticationToken extends AbstractAuthenticationToken {
  private final Set<String> scopes;
  private final Object principal;
  private Object credentials;
  private final Map<String, Object> additionalParameters;
  private final AuthorizationGrantType authorizationGrantType;


  public IamAuthenticationToken(Authentication principal, @Nullable Set<String> scopes, @Nullable Map<String, Object> additionalParameters) {
    super((Collection)null);

    Assert.notNull(principal, "clientPrincipal cannot be null");
    this.scopes = Collections.unmodifiableSet(scopes != null ? new HashSet<>(scopes) : Collections.emptySet());
    this.additionalParameters = Collections.unmodifiableMap((Map)(additionalParameters != null ? new HashMap(additionalParameters) : Collections.emptyMap()));
    this.principal = principal;
    this.authorizationGrantType = new AuthorizationGrantType("iam");
  }

  public  IamAuthenticationToken(Object principal, Object credentials) {
    super((Collection)null);
    this.principal = principal;
    this.credentials = credentials;
    this.setAuthenticated(false);
    this.authorizationGrantType = new AuthorizationGrantType("iam");
    this.additionalParameters = Collections.emptyMap();
    this.scopes = Collections.emptySet();
  }

  public IamAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
    super(authorities);
    this.principal = principal;
    this.credentials = credentials;
    super.setAuthenticated(true);
    this.authorizationGrantType = new AuthorizationGrantType("iam");
    this.additionalParameters = Collections.emptyMap();
    this.scopes = Collections.emptySet();
  }

  public static IamAuthenticationToken unauthenticated(Object principal, Object credentials) {
    return new IamAuthenticationToken(principal, credentials);
  }

  public static IamAuthenticationToken authenticated(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
    return new IamAuthenticationToken(principal, credentials, authorities);
  }

  public Map<String, Object> getAdditionalParameters() {
    return this.additionalParameters;
  }

  public Set<String> getScopes() {
    return this.scopes;
  }

  public Object getCredentials() {
    return this.credentials;
  }

  public Object getPrincipal() {
    return this.principal;
  }

  public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
    Assert.isTrue(!isAuthenticated, "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
    super.setAuthenticated(false);
  }

  public void eraseCredentials() {
    super.eraseCredentials();
    this.credentials = null;
  }
}
